#include "STC8Hxxx.H"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "delay.h"
#include "oled.h"
#include "MatrixKey.h"

// #define MAIN_Fosc   11059200L   // ??????????

// typedef long	uint16_t;

typedef struct {
    uint32_t num;
    uint16_t len;
} Number;

Number num1 = {0, 0};
Number num2 = {0, 0};
Number Result = {0, 0};

unsigned char key = 0;
char operator = ' ';
char A1[20] = {0};
char A2[20] = {0};
char R[20] = {0};

void show_in(void);
unsigned char key_decode(unsigned char key);
Number compute(char operator, Number *num1, Number *num2);
void num_in(uint32_t nn, Number *N);

void main()
{   
    P_SW2 |= 0x80;                          // ??????????XFR?????????

    OLED_Init();
    OLED_ColorTurn(0);
    OLED_DisplayTurn(0);

    OLED_Clear();
    OLED_ShowString(4, 0, "STC Calculutor", 16);

    MatrixKey_Init();

    Delay1000ms();

    OLED_Clear();
    show_in();

    while (1)
    {
        key = MatrixKey();
        if (key != 0) {
            show_in();
            
            switch (key)
            {
            case 20: {
                operator = ' ';
                num1.num = 0;
                num1.len = 0;
                num2.num = 0;
                num2.len = 0;
                Result.num = 0;
                Result.len = 0;
                OLED_Clear();
                show_in();
            } break;
            case 16: {
                show_in();
                Result = compute(operator, &num1, &num2);
                if (Result.num > 999999999) {
                    OLED_Clear();
                    Result.num = 0;
                    Result.len = 0;
                    num1.num = 0;
                    num1.len = 0;
                    num2.num = 0;
                    num2.len = 0;
                    operator = ' ';
                    show_in();
                }
                sprintf(R, "%12ld", Result.num);
                OLED_ShowString(12, 6, R, 16);
                // OLED_ShowNum(0, 6, result, 14, 16);
                num1.num = Result.num;
                num1.len = Result.len;
                // num2.num = 0; num2.len = 0;
            } break;
            case 12: {
                operator = '+';
                if (num1.len > 0 && num2.len > 0) {
                    num1.num = Result.num; num1.len = Result.len;
                }
                num2.num = 0; num2.len = 0; 
                OLED_Clear(); show_in(); break;
                }
            case  8: {
                operator = '-'; 
                // num1.num = Result.num; num1.len = Result.len;
                num2.num = 0; num2.len = 0; 
                OLED_Clear(); show_in(); break;
                }
            case  4: {
                operator = '*'; 
                // num1.num = Result.num; num1.len = Result.len;
                num2.num = 0; num2.len = 0; 
                OLED_Clear(); show_in(); break;
                }
            case 15: {
                operator = '/'; 
                // num1.num = Result.num; num1.len = Result.len;
                num2.num = 0; num2.len = 0; 
                OLED_Clear(); show_in(); break;
                }
            case 14: {
                operator = ' ';
                num1.num = 0;
                num1.len = 0;
                num2.num = 0;
                num2.len = 0;
                OLED_Clear();
                show_in();
            } break;
            
            default: {
                uint32_t nn = (int)key_decode(key);
                if(operator != ' ') {
                    num_in(nn, &num2);
                    show_in();
                } else {
                    num_in(nn, &num1);
                    show_in();
                }
            } break;
            }
        }
    }
}

/**
 * 7 8 9 *       1  2  3  4
 * 4 5 6 -       5  6  7  8
 * 1 2 3 +       9 10 11 12
 * 0 . / =      13 14 15 16
*/
unsigned char key_decode(unsigned char key)
{
    switch (key)
    {
    case 1: return 7; break;
    case 2: return 8; break;
    case 3: return 9; break;
    case 4: return '*'; break;

    case 5: return 4; break;
    case 6: return 5; break;
    case 7: return 6; break;
    case 8: return '-'; break;

    case  9: return 1; break;
    case 10: return 2; break;
    case 11: return 3; break;
    case 12: return '+'; break;

    case 13: return 0; break;
    case 14: return '.'; break;
    case 15: return '/'; break;
    case 16: return '='; break;

    default: return 'c'; break;
    }
}

Number compute(char operator, Number *num1, Number *num2)
{
    Number Result;
    uint32_t result;

    switch (operator)
    {
    case '+': result = num1->num + num2->num; break;
    case '-': result = num1->num - num2->num; break;
    case '*': result = num1->num * num2->num; break;
    case '/': result = num1->num / num2->num; break;
    // case '.': num1->num = 1; num2->num = 4294967295; show_in(); break;
    
    default: result = 0; break;
    }
    if (result != 0) {
        Result.num = result;
        Result.len = 0;
        while (result > 0) {
            result = result / 10;
            Result.len++;
        }
    }

    return Result;
}

void show_in(void)
{
    // OLED_Clear();
    if (num1.len == 0) {
        if (operator == ' ') {
            OLED_ShowChar(12, 0, '#', 16);
        }
    } else {
        if (num1.num > 999999999) {
            OLED_Clear();
            Result.num = 0;
            Result.len = 0;
            num1.num = 0;
            num1.len = 0;
            // num2.num = 0;
            // num2.len = 0;
            operator = ' ';
            show_in();
            }
        sprintf(A1, "%12ld", num1.num);
        OLED_ShowString(12, 0, A1, 16);
    }

    if (num2.len == 0) {
        if (operator != ' ') {
            OLED_ShowChar(12, 2, '#', 16);
        }
    } else {
        if (num2.num > 999999999) {
            OLED_Clear();
            Result.num = 0;
            Result.len = 0;
            // num1.num = 0;
            // num1.len = 0;
            num2.num = 0;
            num2.len = 0;
            operator = ' ';
            show_in();
            }
        sprintf(A2, "%12ld", num2.num);
        OLED_ShowString(12, 2, A2, 16);
    }
    OLED_ShowChar(0, 2, operator, 16);

    OLED_ShowNum(120, 0, (num1.len), 1, 16);
    OLED_ShowNum(120, 2, (num2.len), 1, 16);
    OLED_ShowNum(120, 6, (Result.len), 1, 16);
}

void num_in(uint32_t nn, Number *N)
{
    if(N->len < 10) {
        N->num = N->num * 10;
        N->num = N->num + (nn % 10);
        N->len++;
        // OLED_ShowNum(0, 6, N->num, 10, 16);
    } else {
        N->num = 0;
        N->len = 0;
        // OLED_ShowNum(0, 6, N->num, 10, 16);
    }
}